#!/usr/bin/python3
"""
Configure the SSH daemon.

The tree must already include /etc/ssh/sshd_config, and it is modified
in place. Every attempt is made to preserve the structure of the file,
though comments are completely ignored.
"""

import fileinput
import sys

import osbuild.api


SCHEMA = """
"additionalProperties": false,
"required": ["config"],
"properties": {
  "config": {
    "additionalProperties": false,
    "description": "SSHD config options",
    "type": "object",
    "properties": {
      "PasswordAuthentication": {
        "description": "Enable or disable password authentication.",
        "type": "boolean"
      },
      "ChallengeResponseAuthentication": {
        "description": "Enable or disable challenge/response authentication.",
        "type": "boolean"
      },
      "ClientAliveInterval": {
        "description": "Number of seconds between keep-alive pings. 0 disables it.",
        "type": "integer"
      },
      "PermitRootLogin": {
        "description": "Specifies whether root can log in using ssh.",
        "oneOf": [
          {
            "enum": ["prohibit-password", "forced-commands-only"],
            "type": "string"
          },
          {
            "type": "boolean"
          }
        ]
      }
    }
  }
}
"""


def bool_to_yes_no(b):
    if b:
        return "yes"
    return "no"


def main(tree, options):
    sshd_config = options.get("config", {})
    password_auth = sshd_config.get("PasswordAuthentication")
    challenge_response_auth = sshd_config.get("ChallengeResponseAuthentication")
    client_alive_interval = sshd_config.get("ClientAliveInterval")
    permit_root_login = sshd_config.get("PermitRootLogin")
    changes = {}
    if password_auth is not None:
        changes["passwordauthentication"] = {
            "key": "PasswordAuthentication",
            "value": bool_to_yes_no(password_auth)
        }
    if challenge_response_auth is not None:
        changes["challengeresponseauthentication"] = {
            "key": "ChallengeResponseAuthentication",
            "value": bool_to_yes_no(challenge_response_auth)
        }
    if client_alive_interval is not None:
        changes["clientaliveinterval"] = {
            "key": "ClientAliveInterval",
            "value": client_alive_interval
        }
    if permit_root_login is not None:
        changes["permitrootlogin"] = {
            "key": "PermitRootLogin",
            "value": bool_to_yes_no(permit_root_login) if isinstance(permit_root_login, bool) else permit_root_login
        }

    # For each of the configured options, find the first non-commented out instance
    # of the option and replace it (if necessary). If it does not already exist, append
    # the option to the end of the file.
    # Keys are case insensitive, values are not. Try to preserve the key and default to
    # camel-case.
    with fileinput.input(files=(f"{tree}/etc/ssh/sshd_config"), inplace=True) as f:
        for line in f:
            line_list = line.split()
            if len(line_list) == 2:
                key, current_value = line_list
                entry = changes.pop(key.lower(), None)
                if entry is not None and current_value != entry['value']:
                    sys.stdout.write(f"{key} {entry['value']}\n")
                    continue
            sys.stdout.write(line)
    with open(f"{tree}/etc/ssh/sshd_config", mode="a") as f:
        for entry in changes.values():
            f.write(f"{entry['key']} {entry['value']}\n")

    return 0


if __name__ == '__main__':
    args = osbuild.api.arguments()
    r = main(args["tree"], args["options"])
    sys.exit(r)
